﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

#Область ДляВызоваИзДругихПодсистем

// СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов

// Возвращает реквизиты объекта, которые разрешается редактировать
// с помощью обработки группового изменения реквизитов.
//
// Возвращаемое значение:
//  Массив из Строка
//
Функция РеквизитыРедактируемыеВГрупповойОбработке() Экспорт
	
	Результат = Новый Массив;
	Возврат Результат;
	
КонецФункции

// Конец СтандартныеПодсистемы.ГрупповоеИзменениеОбъектов

#КонецОбласти

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Возвращает ссылку на справочник внешней компоненты по идентификатору и версии.
//
// Параметры:
//  Идентификатор - Строка - идентификатор объекта внешнего компонента.
//  Версия        - Строка - версия компоненты.
//
// Возвращаемое значение:
//  СправочникСсылка.ВнешниеКомпоненты - ссылка на контейнер внешней компоненты в информационной базе.
//
Функция НайтиПоИдентификатору(Идентификатор, Версия = Неопределено) Экспорт
	
	Запрос = Новый Запрос;
	Запрос.УстановитьПараметр("Идентификатор", Идентификатор);
	
	Если Не ЗначениеЗаполнено(Версия) Тогда 
		Запрос.Текст = 
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	ВнешниеКомпоненты.Идентификатор КАК Идентификатор,
			|	ВнешниеКомпоненты.ДатаВерсии КАК ДатаВерсии,
			|	ВЫБОР
			|		КОГДА ВнешниеКомпоненты.Использование = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияВнешнихКомпонент.Используется)
			|			ТОГДА ИСТИНА
			|		ИНАЧЕ ЛОЖЬ
			|	КОНЕЦ КАК Использование,
			|	ВнешниеКомпоненты.Ссылка КАК Ссылка
			|ИЗ
			|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
			|ГДЕ
			|	ВнешниеКомпоненты.Идентификатор = &Идентификатор
			|
			|УПОРЯДОЧИТЬ ПО
			|	Использование УБЫВ,
			|	ДатаВерсии УБЫВ";
	Иначе 
		Запрос.УстановитьПараметр("Версия", Версия);
		Запрос.Текст = 
			"ВЫБРАТЬ ПЕРВЫЕ 1
			|	ВнешниеКомпоненты.Ссылка КАК Ссылка,
			|	ВЫБОР
			|		КОГДА ВнешниеКомпоненты.Использование = ЗНАЧЕНИЕ(Перечисление.ВариантыИспользованияВнешнихКомпонент.Используется)
			|			ТОГДА ИСТИНА
			|		ИНАЧЕ ЛОЖЬ
			|	КОНЕЦ КАК Использование
			|ИЗ
			|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты
			|ГДЕ
			|	ВнешниеКомпоненты.Идентификатор = &Идентификатор
			|	И ВнешниеКомпоненты.Версия = &Версия
			|
			|УПОРЯДОЧИТЬ ПО
			|	Использование УБЫВ";
		
	КонецЕсли;
	
	Результат = Запрос.Выполнить();
	
	Если Результат.Пустой() Тогда 
		Возврат ПустаяСсылка();
	КонецЕсли;
	
	Выборка = Результат.Выбрать();
	Выборка.Следующий();
	
	Возврат Результат.Выгрузить()[0].Ссылка;
	
КонецФункции

#Область ОбработчикиОбновления

// Регистрирует на плане обмена ОбновлениеИнформационнойБазы объекты,
// которые необходимо обновить на новую версию.
//
Процедура ЗарегистрироватьДанныеКОбработкеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Параметры.ВерсияПодсистемыНаНачалоОбновления, "3.1.9.221") < 0 Тогда
	
		ТекстЗапроса ="ВЫБРАТЬ
		|	ВнешниеКомпоненты.Ссылка
		|ИЗ
		|	Справочник.ВнешниеКомпоненты КАК ВнешниеКомпоненты";
		
		Запрос = Новый Запрос(ТекстЗапроса);
		
		ОбновлениеИнформационнойБазы.ОтметитьКОбработке(Параметры, Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка"));

	КонецЕсли;
	
КонецПроцедуры

// Обработчик обновления справочника "Внешние компоненты":
// - заполняет реквизит ЦелевыеПлатформы;
// - для возможности автообновления добавляет внешние компоненты ExtraCryptoAPI, сканирования и печати штрихкодов.
//
Процедура ОбработатьДанныеДляПереходаНаНовуюВерсию(Параметры) Экспорт
	Параметры.ОбработкаЗавершена = Истина;
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Параметры.ВерсияПодсистемыНаНачалоОбновления, "3.1.5.220") < 0
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ЭлектроннаяПодпись")
		И ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент")
		И Не ОбщегоНазначения.РазделениеВключено() Тогда
		
		ИспользуемыеКомпоненты = ВнешниеКомпонентыСервер.ИспользуемыеКомпоненты("ДляЗагрузки");
		
		Если ИспользуемыеКомпоненты.Найти("ExtraCryptoAPI", "Идентификатор") = Неопределено Тогда 
		
			МодульЭлектроннаяПодписьСлужебныйКлиентСервер = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебныйКлиентСервер");
			МодульЭлектроннаяПодписьСлужебный = ОбщегоНазначения.ОбщийМодуль("ЭлектроннаяПодписьСлужебный");
			
			ОписаниеКомпоненты = МодульЭлектроннаяПодписьСлужебныйКлиентСервер.ОписаниеКомпоненты();
			КомпонентаПоследнейВерсииИзМакета = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии(
				ОписаниеКомпоненты.ИмяОбъекта, ОписаниеКомпоненты.ПолноеИмяМакета);
			
			МестоположениеМакетаРазделенное = СтрРазделить(КомпонентаПоследнейВерсииИзМакета.Местоположение, ".");
			
			ДвоичныеДанные = МодульЭлектроннаяПодписьСлужебный.ПолучитьДанныеКомпоненты(
				МестоположениеМакетаРазделенное.Получить(МестоположениеМакетаРазделенное.ВГраница()));
				
			ПараметрыКомпоненты = ВнешниеКомпонентыСлужебный.ПараметрыЗагрузки();
			ПараметрыКомпоненты.Идентификатор = ОписаниеКомпоненты.ИмяОбъекта;
			ПараметрыКомпоненты.Наименование = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru='%1 для 1С:Предприятие'", ОбщегоНазначения.КодОсновногоЯзыка()), "ExtraCryptoAPI");
			ПараметрыКомпоненты.Версия = КомпонентаПоследнейВерсииИзМакета.Версия;
			ПараметрыКомпоненты.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Добавлена автоматически %1.'", ОбщегоНазначения.КодОсновногоЯзыка()), ТекущаяДатаСеанса());
			ПараметрыКомпоненты.ОбновлятьСПортала1СИТС = Истина;
			ПараметрыКомпоненты.Данные = ДвоичныеДанные;
			
			ВнешниеКомпонентыСлужебный.ЗагрузитьКомпонентуИзДвоичныхДанных(ПараметрыКомпоненты, Ложь);
		КонецЕсли;
	
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Параметры.ВерсияПодсистемыНаНачалоОбновления, "3.1.9.163") < 0
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.РаботаСФайлами")
		И ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент")
		И Не ОбщегоНазначения.РазделениеВключено() Тогда
		
		ИспользуемыеКомпоненты = ВнешниеКомпонентыСервер.ИспользуемыеКомпоненты("ДляЗагрузки");
		МодульРаботаСФайламиСлужебныйКлиентСервер = ОбщегоНазначения.ОбщийМодуль("РаботаСФайламиСлужебныйКлиентСервер");
			
		ОписаниеКомпоненты = МодульРаботаСФайламиСлужебныйКлиентСервер.ОписаниеКомпоненты();
		
		Если ИспользуемыеКомпоненты.Найти(ОписаниеКомпоненты.ИмяОбъекта, "Идентификатор") = Неопределено Тогда 
		
			КомпонентаПоследнейВерсииИзМакета = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии(
				ОписаниеКомпоненты.ИмяОбъекта, ОписаниеКомпоненты.ПолноеИмяМакета);
			
			МестоположениеМакетаРазделенное = СтрРазделить(КомпонентаПоследнейВерсииИзМакета.Местоположение, ".");
			ДвоичныеДанные = ПолучитьОбщийМакет(МестоположениеМакетаРазделенное.Получить(МестоположениеМакетаРазделенное.ВГраница()));
				
			ПараметрыКомпоненты = ВнешниеКомпонентыСлужебный.ПараметрыЗагрузки();
			ПараметрыКомпоненты.Идентификатор = ОписаниеКомпоненты.ИмяОбъекта;
			ПараметрыКомпоненты.Наименование = НСтр("ru='Компонента для сканирования документов и изображений'");
			ПараметрыКомпоненты.Версия = КомпонентаПоследнейВерсииИзМакета.Версия;
			ПараметрыКомпоненты.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Добавлена автоматически %1.'"), ТекущаяДатаСеанса());
			ПараметрыКомпоненты.ОбновлятьСПортала1СИТС = Истина;
			ПараметрыКомпоненты.Данные = ДвоичныеДанные;
			
			ВнешниеКомпонентыСлужебный.ЗагрузитьКомпонентуИзДвоичныхДанных(ПараметрыКомпоненты, Ложь);
		КонецЕсли;
		
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Параметры.ВерсияПодсистемыНаНачалоОбновления, "3.1.9.221") < 0 Тогда
		
		Выборка = ОбновлениеИнформационнойБазы.ВыбратьСсылкиДляОбработки(Параметры.Очередь, "Справочник.ВнешниеКомпоненты");
		Если Выборка.Количество() > 0 Тогда
			ОбработатьВнешниеКомпоненты(Выборка);
		КонецЕсли;

		ОбработкаЗавершена = ОбновлениеИнформационнойБазы.ОбработкаДанныхЗавершена(Параметры.Очередь,
			"Справочник.ВнешниеКомпоненты");
		Параметры.ОбработкаЗавершена = ОбработкаЗавершена;
	
	КонецЕсли;
	
	Если ОбщегоНазначенияКлиентСервер.СравнитьВерсии(Параметры.ВерсияПодсистемыНаНачалоОбновления, "3.1.9.224") < 0
		И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ГенерацияШтрихкода")
		И ОбщегоНазначения.ПодсистемаСуществует("ИнтернетПоддержкаПользователей.ПолучениеВнешнихКомпонент")
		И Не ОбщегоНазначения.РазделениеВключено() Тогда
		
		ИспользуемыеКомпоненты = ВнешниеКомпонентыСервер.ИспользуемыеКомпоненты("ДляЗагрузки");
		МодульГенерацияШтрихкода = ОбщегоНазначения.ОбщийМодуль("ГенерацияШтрихкода");
			
		ОписаниеКомпоненты = МодульГенерацияШтрихкода.ОписаниеКомпоненты();
		
		Если ИспользуемыеКомпоненты.Найти(ОписаниеКомпоненты.ИмяОбъекта, "Идентификатор") = Неопределено Тогда 
		
			КомпонентаПоследнейВерсииИзМакета = СтандартныеПодсистемыСервер.КомпонентаПоследнейВерсии(
				ОписаниеКомпоненты.ИмяОбъекта, ОписаниеКомпоненты.ПолноеИмяМакета);
			
			МестоположениеМакетаРазделенное = СтрРазделить(КомпонентаПоследнейВерсииИзМакета.Местоположение, ".");
			ДвоичныеДанные = ПолучитьОбщийМакет(МестоположениеМакетаРазделенное.Получить(МестоположениеМакетаРазделенное.ВГраница()));
				
			ПараметрыКомпоненты = ВнешниеКомпонентыСлужебный.ПараметрыЗагрузки();
			ПараметрыКомпоненты.Идентификатор = ОписаниеКомпоненты.ИмяОбъекта;
			ПараметрыКомпоненты.Наименование = НСтр("ru='Компонента для генерации штрихкодов'");
			ПараметрыКомпоненты.Версия = КомпонентаПоследнейВерсииИзМакета.Версия;
			ПараметрыКомпоненты.ОписаниеОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Добавлена автоматически %1.'"), ТекущаяДатаСеанса());
			ПараметрыКомпоненты.ОбновлятьСПортала1СИТС = Истина;
			ПараметрыКомпоненты.Данные = ДвоичныеДанные;
			
			ВнешниеКомпонентыСлужебный.ЗагрузитьКомпонентуИзДвоичныхДанных(ПараметрыКомпоненты, Ложь);
		КонецЕсли;
		
	КонецЕсли;
	
КонецПроцедуры

// Параметры:
//   Выборка - ВыборкаИзРезультатаЗапроса:
//     * Ссылка - СправочникСсылка.ВнешниеКомпоненты
//
Процедура ОбработатьВнешниеКомпоненты(Выборка)
	
	ОбъектовОбработано = 0;
	ПроблемныхОбъектов = 0;

	Пока Выборка.Следующий() Цикл

		РеквизитыКомпоненты = ОбщегоНазначения.ЗначенияРеквизитовОбъекта(Выборка.Ссылка,
			"ХранилищеКомпоненты, ЦелевыеПлатформы");
		
		ЦелевыеПлатформы = РеквизитыКомпоненты.ЦелевыеПлатформы.Получить();
		
		ДвоичныеДанныеКомпоненты = РеквизитыКомпоненты.ХранилищеКомпоненты.Получить();
		
		Если ТипЗнч(ДвоичныеДанныеКомпоненты) <> Тип("ДвоичныеДанные") Тогда
			ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(Выборка.Ссылка);
			ОбъектовОбработано = ОбъектовОбработано + 1;
			Продолжить;
		КонецЕсли;
		
		ИнформацияОКомпонентеИзФайла = ВнешниеКомпонентыСлужебный.ИнформацияОКомпонентеИзФайла(
			ДвоичныеДанныеКомпоненты, Ложь);
		Если Не ИнформацияОКомпонентеИзФайла.Разобрано Тогда
			ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(Выборка.Ссылка);
			ОбъектовОбработано = ОбъектовОбработано + 1;
			Продолжить;
		КонецЕсли;
		
		Реквизиты = ИнформацияОКомпонентеИзФайла.Реквизиты;
		
		Если ЦелевыеПлатформы <> Неопределено И ОбщегоНазначения.КоллекцииИдентичны(ЦелевыеПлатформы, Реквизиты.ЦелевыеПлатформы) Тогда
			ОбновлениеИнформационнойБазы.ОтметитьВыполнениеОбработки(Выборка.Ссылка);
			ОбъектовОбработано = ОбъектовОбработано + 1;
			Продолжить;
		КонецЕсли;
		
		ПредставлениеСсылки = Строка(Выборка.Ссылка);
		НачатьТранзакцию();
		Попытка

			Блокировка = Новый БлокировкаДанных;
			ЭлементБлокировки = Блокировка.Добавить("Справочник.ВнешниеКомпоненты");
			ЭлементБлокировки.УстановитьЗначение("Ссылка", Выборка.Ссылка);
			ЭлементБлокировки.Режим = РежимБлокировкиДанных.Разделяемый;
			Блокировка.Заблокировать();

			КомпонентаОбъект = Выборка.Ссылка.ПолучитьОбъект(); // СправочникОбъект.ВнешниеКомпоненты
			КомпонентаОбъект.ЦелевыеПлатформы = Новый ХранилищеЗначения(Реквизиты.ЦелевыеПлатформы);
			ОбновлениеИнформационнойБазы.ЗаписатьОбъект(КомпонентаОбъект);

			ОбъектовОбработано = ОбъектовОбработано + 1;
			ЗафиксироватьТранзакцию();

		Исключение

			ОтменитьТранзакцию();
			// Если не удалось обработать компоненту, повторяем попытку снова.
			ПроблемныхОбъектов = ПроблемныхОбъектов + 1;

			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не удалось обработать компоненту %1 по причине:
					 |%2'"), ПредставлениеСсылки, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));

			ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(),
				УровеньЖурналаРегистрации.Предупреждение, Выборка.Ссылка.Метаданные(), Выборка.Ссылка, ТекстСообщения);

		КонецПопытки;

	КонецЦикла;

	Если ОбъектовОбработано = 0 И ПроблемныхОбъектов <> 0 Тогда
		ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось обработать некоторые компоненты (пропущены): %1'"),
			ПроблемныхОбъектов);
		ВызватьИсключение ТекстСообщения;
	Иначе
		ЗаписьЖурналаРегистрации(ОбновлениеИнформационнойБазы.СобытиеЖурналаРегистрации(),
			УровеньЖурналаРегистрации.Информация, Метаданные.Справочники.ВнешниеКомпоненты,,
				СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Обработана очередная порция компонент: %1'"),
			ОбъектовОбработано));
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#КонецОбласти

#КонецЕсли